<template>
  <el-upload
    v-model:file-list="fileList"
    :http-request="handleUpload"
    :before-upload="beforeUpload"
    :on-success="onSuccess"
    :on-error="onError"
    :on-progress="onProgress"
    :accept="accept"
    :limit="limit"
    :disabled="disabled"
    :show-file-list="showFileList"
    :auto-upload="autoUpload"
  >
    <slot name="trigger">
      <el-button type="primary" :loading="uploading">
        <UploadIcon v-if="uploading" class="mr-2" />
        {{ buttonText }}
      </el-button>
    </slot>
    <template #file-list>
      <div v-if="showFileList" class="file-list-container">
        <el-row :gutter="[0, 10]">
          <el-col v-for="(file, index) in fileList" :key="index" :span="24">
            <el-card
              :body-style="{ padding: '10px' }"
              :bordered="false"
              class="file-item"
            >
              <div class="file-info">
                <span class="file-name">{{ file.name }}</span>
                <span class="file-size">{{ formatFileSize(file.size) }}</span>
              </div>
              <div class="file-actions">
                <el-progress
                  v-if="file.progress !== undefined"
                  :percentage="file.progress"
                  :status="
                    file.status === 'success'
                      ? 'success'
                      : file.status === 'error'
                      ? 'exception'
                      : 'normal'
                  "
                  class="progress"
                />
                <el-button
                  v-if="canDeleteFile(file)"
                  icon="Delete"
                  size="small"
                  type="danger"
                  @click.stop="handleDelete(index)"
                />
              </div>
            </el-card>
          </el-col>
        </el-row>
      </div>
    </template>
  </el-upload>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, defineProps, defineEmits } from "vue";
import {
  Upload as UploadIcon,
  Check,
  Close,
  Delete,
} from "@element-plus/icons-vue";
import { uploadFile, OSS_DIR } from "@/api/oss";
import { ElMessage } from "element-plus";

// 定义组件props
const props = defineProps({
  // OSS目录类型
  ossDir: {
    type: String,
    required: true,
    validator: (value: string) => {
      return Object.values(OSS_DIR).includes(value as OSS_DIR);
    },
  },
  // 允许上传的文件类型
  accept: {
    type: String,
    default: "*",
  },
  // 最大上传数量
  limit: {
    type: Number,
    default: 10,
  },
  // 是否禁用上传
  disabled: {
    type: Boolean,
    default: false,
  },
  // 是否显示文件列表
  showFileList: {
    type: Boolean,
    default: true,
  },
  // 是否自动上传
  autoUpload: {
    type: Boolean,
    default: true,
  },
  // 按钮文本
  buttonText: {
    type: String,
    default: "上传文件",
  },
  // 初始文件列表
  initialFiles: {
    type: Array,
    default: () => [],
  },
});

// 定义组件emits
const emit = defineEmits([
  "upload-success",
  "upload-error",
  "upload-progress",
  "file-removed",
  "change",
]);

// 组件内部状态
const fileList = ref<any[]>([]);
const uploading = ref(false);
const currentUploadIndex = ref(-1);

// 格式化文件大小
const formatFileSize = (size: number): string => {
  if (size < 1024) {
    return `${size} B`;
  } else if (size < 1024 * 1024) {
    return `${(size / 1024).toFixed(2)} KB`;
  } else {
    return `${(size / (1024 * 1024)).toFixed(2)} MB`;
  }
};

// 检查是否可以删除文件
const canDeleteFile = (file: any): boolean => {
  return file.status !== "uploading";
};

// 上传前检查
const beforeUpload = (file: File): boolean => {
  // 检查文件类型
  if (props.accept !== "*") {
    const acceptTypes = props.accept.split(",").map((type) => type.trim());
    const fileExtension = file.name.split(".").pop()?.toLowerCase() || "";
    const isAccept = acceptTypes.some((type) => {
      if (type.startsWith(".")) {
        return type.toLowerCase() === `.${fileExtension}`;
      } else if (type.includes("/")) {
        return file.type.startsWith(type.split("/")[0]);
      }
      return false;
    });
    // TODO: 检查文件点击次数
    if (!isAccept) {
      ElMessage.error(`不支持的文件类型: ${fileExtension}`);
      return false;
    }
  }

  // 检查文件数量
  if (fileList.value.length >= props.limit) {
    ElMessage.error(`最多只能上传 ${props.limit} 个文件`);
    return false;
  }

  return true;
};

const calculateFileHash = async (file: File): Promise<string> => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      const arrayBuffer = e.target?.result as ArrayBuffer;
      const uint8Array = new Uint8Array(arrayBuffer);
      // 这里使用简单的哈希算法，实际项目中可以使用更复杂的算法
      let hash = 0;
      for (let i = 0; i < uint8Array.length; i++) {
        hash = (hash << 5) - hash + uint8Array[i];
        hash |= 0; // 转换为32位整数
      }
      resolve(Math.abs(hash).toString(16));
    };
    reader.readAsArrayBuffer(file);
  });
};

// 处理上传
const handleUpload = async (options: any) => {
  const file = options.file;
  const index = fileList.value.findIndex((f) => f.uid === file.uid);

  if (index === -1) {
    // 添加新文件到列表
    fileList.value.push({
      ...file,
      status: "uploading",
      progress: 0,
    });
    currentUploadIndex.value = fileList.value.length - 1;
  } else {
    // 更新现有文件状态
    fileList.value[index].status = "uploading";
    fileList.value[index].progress = 0;
    currentUploadIndex.value = index;
  }

  uploading.value = true;

  try {
    // 生成随机文件名，避免覆盖
    // const timestamp = Date.now();
    // const randomString = Math.random().toString(36).substring(2, 10);
    // const fileExtension = file.name.split(".").pop() || "";
    // const fileName = `${timestamp}_${randomString}.${fileExtension}`;
    // 计算文件哈希值
    const fileHash = await calculateFileHash(file);
    const fileExtension = file.name.split('.').pop() || '';
    const fileName = `${fileHash}.${fileExtension}`;

    // 调用OSS上传接口
    const result = await uploadFile(file, fileName, props.ossDir as OSS_DIR);

    // 更新文件状态
    fileList.value[currentUploadIndex.value].status = "success";
    fileList.value[currentUploadIndex.value].progress = 100;
    fileList.value[currentUploadIndex.value].url = result;

    // 触发成功事件
    emit("upload-success", result, fileList.value[currentUploadIndex.value]);
    ElMessage.success("文件上传成功");
  } catch (error) {
    // 更新文件状态
    fileList.value[currentUploadIndex.value].status = "error";

    // 触发失败事件
    emit("upload-error", error, fileList.value[currentUploadIndex.value]);
    ElMessage.error("文件上传失败");
  } finally {
    uploading.value = false;
  }
};

// 上传成功回调
const onSuccess = (response: any, file: any, fileList: any[]) => {
  // 这里不需要实现，因为我们使用了自定义的http-request
};

// 上传失败回调
const onError = (error: any, file: any, fileList: any[]) => {
  // 这里不需要实现，因为我们使用了自定义的http-request
};

// 上传进度回调
const onProgress = (event: any, file: any, fileList: any[]) => {
  const index = fileList.value.findIndex((f) => f.uid === file.uid);
  if (index !== -1) {
    const progress = Math.round((event.percent || 0) * 100);
    fileList.value[index].progress = progress;
    emit("upload-progress", progress, fileList.value[index]);
  }
};

// 处理删除文件
const handleDelete = (index: number) => {
  const removedFile = fileList.value[index];
  fileList.value.splice(index, 1);
  emit("file-removed", removedFile);
  emit("change", fileList.value);
};

// 初始化文件列表
onMounted(() => {
  if (props.initialFiles && props.initialFiles.length > 0) {
    fileList.value = props.initialFiles.map((file) => ({
      ...file,
      status: "success",
      progress: 100,
    }));
    emit("change", fileList.value);
  }
});

// 导出组件内部状态和方法
defineExpose({
  fileList,
  uploadFile: handleUpload,
  deleteFile: handleDelete,
  clearFiles: () => {
    fileList.value = [];
    emit("change", fileList.value);
  },
});
</script>

<style scoped lang="less">
.file-list-container {
  margin-top: 16px;
}

.file-item {
  .file-info {
    display: flex;
    align-items: center;
    margin-bottom: 8px;

    .file-icon {
      font-size: 18px;
    }

    .file-name {
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .file-size {
      font-size: 12px;
      color: #909399;
      margin-left: 8px;
    }
  }

  .file-actions {
    .progress {
      margin-bottom: 8px;
    }

    .file-status {
      margin-bottom: 8px;

      .success-text {
        color: #67c23a;
      }

      .error-text {
        color: #f56c6c;
      }
    }
  }
}
</style>
